#!/bin/sh
timestamp() {
        date '+%Y-%m-%d %H:%M:%S'
}
start=$(date +%s)
printf "%s: start\n" "`timestamp`"

# ALL VARIABLES STARTING WITH % WILL BE REPLACED BY BUTCH
# WITH VALUES TAKEN FROM THE PKG FILE.

# BUTCH_CONFIG will get replaced by the environment variables
# that butch uses (R,S,C...).
%BUTCH_CONFIG

test -z "$K" -o -z "$S" && {
	echo "ERROR: K not passed in BUTCH_CONFIG">&2
	exit 1
}

# early exit when producing a build script for a package without build
# section.
test "$skip_build" = true && exit 0

BUTCH_HAVE_TARBALL=false
[ -n "%BUTCH_MIRROR_URLS" ] || [ -n "$tarball" ] && BUTCH_HAVE_TARBALL=true
get_file_name() {
printf "%s" "$1" | awk '{n=split($0,a,"/");print a[n];}'
}
get_file_ext() {
printf "%s" "$1" | awk '{n=split($0,a,".");print a[n];}'
}
strip_file_ext() {
case "$1" in
*.tar.*) printf "%s\n" "$1"| sed 's/\.tar\.[0-9a-z]*$//' ;;
*) le=$(get_file_ext "$1"| wc -c)
   ls=$(printf "%s" "$1"|wc -c)
   l=$(($ls - $le))
   printf "%s" "$1"|cut -b -$l
   ;;
esac
}
if [ -z "$tarball" ] && $BUTCH_HAVE_TARBALL ; then
for i in %BUTCH_MIRROR_URLS ; do
	tarball=$(get_file_name "$i")
	break
done
fi

BUTCH_TARBALL="$tarball"
if [ -z "$tardir" ] && $BUTCH_HAVE_TARBALL ; then
	tardir=$(strip_file_ext "$tarball")
fi
BUTCH_TARDIR="$tardir"

[ -z "$B" ] && B=$S/build

# some settings to influence this script...
# note that you could set similar stuff using env variables.
butch_do_config_cache=true
butch_do_cleanup_builddir_prebuild=true
[ -z "$butch_do_delete_libtool_archives" ] && butch_do_delete_libtool_archives=true
[ -z "$butch_do_compress_manpages" ] && butch_do_compress_manpages=true
[ -z "$butch_do_cleanup_builddir_postbuild" ] && butch_do_cleanup_builddir_postbuild=false

[ -z "$butch_do_custom_destdir" ] && butch_do_custom_destdir=true
# tardir_create can be set to true in a package's var section if the tarball/zip
# extracts to the current directory. this allows to first create the tardir and
# cleanly unpack into that.
butch_tardir_create=false
[ "$tardir_create" = 1 ] && butch_tardir_create=true

if $butch_do_custom_destdir ; then
	butch_do_cleanup_custom_destdir=true
	[ "$no_unlink" = 1 ] && butch_do_cleanup_custom_destdir=false
	[ -z "$butch_do_relocate" ] && butch_do_relocate=true
	[ -z "$butch_do_filelists" ] && butch_do_filelists=true
	[ -z "$butch_do_create_tarball" ] && butch_do_create_tarball=false
	[ -z "$butch_do_separate_debug_info" ] && butch_do_separate_debug_info=true
	[ -z "$butch_do_strip_comments" ] && butch_do_strip_comments=false
	[ -z "$butch_do_overwrite_on_copy" ] && butch_do_overwrite_on_copy=false
fi


[ -z "$butch_filelists" ] && butch_filelists="$S/filelists/"
[ -z "$butch_tarballs_used" ] && butch_tarballs_used="$S/tarballs_used.txt"
[ -z "$butch_pack_dest" ] && butch_pack_dest="$S/dist/"

butch_package_name=%BUTCH_PACKAGE_NAME
[ -z "$butch_package_name" ] && {
	echo "ERROR: butch_package_name missing">&2
	exit 1
}
butch_prefix=/

filelist="$butch_filelists/$butch_package_name.txt"

# making the prefix empty instead of / seems like a good idea to not get ugly double slashes
# when concatenating paths. however this leads to multiple issues in buggy packages,
# but these have been fixed now (see openssl-dynamic, perl, xcb-proto for reference).
[ "$butch_prefix" = "/" ] && butch_prefix=
# butch_root_dir contains the root path passed in $R.
# once inside the chroot, it is /. we use the butch variable in case a script overwrites $R,
# and in order to be able to swap it out easily once i decided to replace the variables with
# a config file or so.
# use it, if you need to reference something that lies in the directory structure.
butch_root_dir="$R"
# butch_staging_dir is where packages get installed into via DESTDIR
# and then linked into $R
[ -z "$butch_staging_dir" ] && butch_staging_dir=/opt
[ "$butch_root_dir" = "/" ] && butch_root_dir=
butch_custom_destdir_base="$butch_staging_dir"/$butch_package_name
butch_custom_destdir="$butch_root_dir""$butch_custom_destdir_base"

#currently passing a version from a package is not implemented.
butch_package_version=0.0.0

butch_install_dir_final=
# butch_install_dir denotes the DESTDIR passed to make
if $butch_do_custom_destdir ; then
	butch_install_dir="$butch_custom_destdir"
	if [ -d "$butch_install_dir" ] ; then
	if $butch_do_cleanup_custom_destdir ; then
		case "$butch_custom_destdir" in
		/|//|///|$butch_staging_dir|$butch_staging_dir/|$butch_staging_dir//)
		echo "ERROR: prevented removal of $butch_custom_destdir">&2
		exit 1 ;;
		esac
		rm -rf "$butch_custom_destdir"
		if [ "$butch_do_filelists" ] && [ -e "$filelist" ] ; then
			"$K"/bin/butch-unlink "$butch_package_name"
			rm -f "$filelist"
		fi
	else
		#  no_unlink package, build into a temporary destdir which we swap out for the real one on success
		butch_install_dir_final="$butch_install_dir"
		butch_custom_destdir_base="$butch_staging_dir"/__tmp__"$butch_package_name"
		butch_custom_destdir="$butch_root_dir""$butch_custom_destdir_base"
		butch_install_dir="$butch_custom_destdir"
	fi
	fi
else
	butch_install_dir=
fi
[ -z "$butch_install_dir" ] || mkdir -p "$butch_install_dir"

#butch_cache_dir is the place where tarballs are found
butch_cache_dir="$C"

# this is were stuff gets extracted to and built in
butch_build_root="$B/$butch_package_name"
butch_build_dir="$butch_build_root/$BUTCH_TARDIR"

#this is the location of our optimized config.cache
butch_config_cache="$K/config.cache"

[ -z "$CC" ]  && CC=cc
[ -z "$CXX" ]  && CXX=c++
[ -z "$HOSTCC" ]  && HOSTCC="$CC"
[ -z "$HOSTCXX" ]  && HOSTCXX="$CXX"

test "$USE_CCACHE" = 1 && type ccache >/dev/null 2>&1 && {
	CC="ccache $CC"
	CXX="ccache $CXX"
}

# supply space-separated list of packages you want to build with SECURE=1
if test -n "$SECURE_PACKAGES"; then
	SECURE=0
	for pkg in $SECURE_PACKAGES; do
		test "$pkg" = "$butch_package_name" && SECURE=1 && break
	done
	export SECURE
fi

debug_build=false
if [ -f "$butch_root_dir"/etc/butch-optflags.sh ] ; then
	user_optimizations_file="$butch_root_dir"/etc/butch-optflags.sh
	printf "%s: sourcing user defined optimization config %s\n" "`timestamp`" "$user_optimizations_file"
	. "$user_optimizations_file"
	printf "%s\n" "$optcflags" | \
		grep -E '(^|\s)[-]g[123]*($|\s)' >/dev/null && \
		debug_build=true
fi

cleanup_builddir() {
	test -d "$butch_build_dir" && \
	test "$butch_build_dir" != "$butch_build_root" && \
	test "${#butch_build_dir}" -gt 4 && \
	test "${#butch_build_dir}" -gt "${#butch_build_root}" && \
	rm -rf "$butch_build_dir"
}
$butch_do_cleanup_builddir_prebuild && cleanup_builddir

if $butch_tardir_create ; then
butch_build_root="$butch_build_dir"
fi
[ -d "$butch_build_root" ] || mkdir -p "$butch_build_root"
cd "$butch_build_root"

# BUTCH_HAVE_TARBALL will be replaced by true or false
# depending on whether a tarball is used by the pkg
if $BUTCH_HAVE_TARBALL ; then

	printf '%s\n' "$BUTCH_TARBALL" >> "$butch_tarballs_used"
	printf "%s: starting to untar\n" "`timestamp`"
	tarflags=
	case $(get_file_ext "$BUTCH_TARBALL") in
		xz) tarflags=-xJf ;;
		lzma) tarflags=-xaf ;;
		bz2) tarflags=-xjf ;;
		gz) tarflags=-xzf ;;
		tgz) tarflags=-xzf ;;
	esac
	# gnu tar has some idiotic behaviour when the user is root...
	if [ "$STAGE" = 0 ] && tar --help 2>&1 | grep no-same-owner >/dev/null ; then
		tarflags="--no-same-owner $tarflags"
	# busybox too, and it doesnt even document the right flag...
	elif [ "$STAGE" = 0 ] ; then
		tryflags=$(printf "%s" "$tarflags"|sed s,x,t,)
		# test if -o flag works.. by listing tar contents
		if tar -o $tryflags "$butch_cache_dir/$BUTCH_TARBALL" | head -n 1 >/dev/null 2>&1 ; then
			tarflags="-o $tarflags"
		fi
	fi
	if [ -z "$tarflags" ] || ! tar $tarflags "$butch_cache_dir/$BUTCH_TARBALL" ; then
		case "$BUTCH_TARBALL" in
			*.tar.xz)
				# old gnu tar passes .xz to lzma instead of xz
				if ! xz -dc "$butch_cache_dir/$BUTCH_TARBALL" | tar x ; then
					echo "tarball error"
					exit 1
				fi ;;
			*.tar.*)
				echo "tarball error"
				exit 1 ;;
			*.zip)
				unzip -o "$butch_cache_dir/$BUTCH_TARBALL" || {
				echo "unzip error"
				exit 1 ; } ;;
			*)
				echo "seems we're not dealing with a tarball"
				echo "handing control to package file..." ;;
		esac
	fi
	printf "%s: untar done\n" "`timestamp`"
	cd "$butch_build_dir"

	if [ -e configure ] ; then
		# fix misdetection of cross-compiles when only --host was given
		sed -i 's/cross_compiling=maybe/cross_compiling=yes/' configure

		# this copies a config.cache template into the actual builddir,
		# so configure skips some timewasting tests
		$butch_do_config_cache && cp -f "$butch_config_cache" .
	fi
fi

printf "%s: start build\n" "`timestamp`"
# python packages "respect" the umask set by the user, unlike all other packages
# which set explicit permissions. non-default umask causes unexpected surprises.
umask_save=$(umask) ; umask 022
build_err_handler() {
test "$?" = 0 && msg="build succeeded without postinstall" || msg="error: build failed"
printf "%s: %s.\n" "`timestamp`" "$msg"
[ -n "$start" ] && printf "total build time: %d seconds.\n" $(($(date +%s) - $start))
}
set -e
trap build_err_handler EXIT

# this will be replaced by the contents of the pkg's [build] section.
%BUTCH_BUILDSCRIPT

trap - EXIT
set +e

umask $umask_save

printf "%s: end build\n" "`timestamp`"

echo "post buildscript phase..."

# install service if package has a servicescript.
[ -n "$service" ] && "$K"/bin/butch-install-service $serviceflags $service "$K"/services/$service

$butch_do_cleanup_builddir_postbuild && cleanup_builddir

# if stuff was directly installed into the rootfs, i.e. without
# butch_do_custom_destdir, any further action is unwanted/impossible
$butch_do_custom_destdir || exit 0

# a package that doesn't want to be handled by the code below this line
# can just call exit 0 as the last statement
# if it wants to get some other stuff handled it could simply override
# butch_install_dir (e.g. for sabotages relocate_toolchain script)

# in case of rebuild of a no_unlink package, swap out contents of the temporary
# staging dir and the already existing permanent one.
if test -n "$butch_install_dir_final" ; then
	# swap out temporary builddir after the build succeeded, in case of no_unlink package.
	flnew=$(mktemp)
	"$K"/bin/butch-genfilelist -D "$butch_install_dir" - | sort -u > "$flnew"
	flold=$(mktemp)
	if [ "$butch_do_filelists" ] && [ -e "$filelist" ] ; then
		sort -u < "$filelist" > "$flold"
	else
		"$K"/bin/butch-genfilelist -D "$butch_install_dir_final" - | sort -u > "$flold"
	fi
	fl=$(mktemp)

	# files contained in both dirs.
	comm -12 "$flold" "$flnew" > "$fl"

	while read fn ; do
		mv "$butch_install_dir"/"$fn" "$butch_install_dir_final"/"$fn"
	done < "$fl"

	# files contained only in new dir.
	comm -13 "$flold" "$flnew" > "$fl"

	while read fn ; do
		mkdir -p "$(dirname "$butch_install_dir_final"/"$fn")"
		mv "$butch_install_dir"/"$fn" "$butch_install_dir_final"/"$fn"
	done < "$fl"

	# files contained only in old dir.
	comm -23 "$flold" "$flnew" > "$fl"

	while read fn ; do
		rm -f "$butch_install_dir_final"/"$fn"
	done < "$fl"
	# overwrite filelist with files only in old dir, so butch unlink can remove stale links.
	mv "$fl" "$filelist"
	"$K"/bin/butch-unlink "$butch_package_name"

	rm -f "$flold" "$flnew" "$filelist"
	rm -rf "$butch_install_dir"
	butch_install_dir="$butch_install_dir_final"
fi

cd "$butch_install_dir"
[ `ls | wc -l` = "0" ] && have_files=false || have_files=true
[ -d share/pkgconfig ] && {
echo "error: package installed pkgconfig files into /share"
echo "please fix package (examples: xtrans eudev libyajl usbutils shared-mime-info)"
exit 1
}
[ -d sbin ] && {
echo "error: package installed binaries into /sbin instead of /bin"
echo "please fix package (examples: openvpn rtmpdump iotop)"
exit 1
}
add_joblist() {
        test -z "$joblist" && joblist="$1" || joblist="$joblist $1"
}
has_bins() {
	[ -d lib ] || [ -d bin ]
}
if $have_files ; then
	if $butch_do_compress_manpages ; then
		have_jf=false
		type jobflow >/dev/null 2>&1 && have_jf=true
		joblist=
		compressor=
		ext=
		if type gzip >/dev/null 2>&1 ; then
			compressor="gzip"
			ext=.gz
		fi
		if type xz >/dev/null 2>&1 && ! xz --help 2>&1 | grep BusyBox>/dev/null 2>&1 ; then
			compressor="xz -z"
			ext=.xz
		fi
		if [ -n "$compressor" ] ; then
			printf "%s: compressing manpages with %s...\n" "$(timestamp)" "$compressor"
			for i in share/man/man*/* ; do
				case "$i" in
					*.gz) continue ;;
					*.bz2) continue ;;
					*.xz) continue ;;
				esac
				new="$i""$ext"
				if [ -L "$i" ] ; then
					ln -sf $(readlink "$i")"$ext" "$new" \
					&& rm -f "$i"
				elif $have_jf ; then
					add_joblist "$i"
				else
					$compressor "$i"
				fi
			done
			if $have_jf && test -n "$joblist" ; then
				cat <<- EOF | sed 's/ /\n/g' | jobflow \
				-threads=$MAKE_THREADS -exec $compressor {}
				$joblist
				EOF
			fi
			printf "%s: done\n" "$(timestamp)"
		fi
	fi
	if has_bins ; then
		strip_debug=false
		if $butch_do_separate_debug_info && $debug_build ; then
			strip_debug=true
			butch_do_strip_comments=false
			printf "%s: stripping debug info into external files...\n" "$(timestamp)"
			mkdir -p lib/debug && chmod 775 lib/debug
		fi
		if $butch_do_strip_comments ; then
			printf "%s: stripping comment section of binaries...\n" "$(timestamp)"
		fi
		for i in lib/*.so* bin/* ; do
			printf "%s" "$i" | grep '\*'>/dev/null && continue
			[ -L "$i" ] || [ -d "$i" ] && continue
			case "$i" in bin*)
				elf=$(dd if="$i" bs=1 skip=1 count=3 2>/dev/null)
				[ "$elf" != "ELF" ] && continue
				if $butch_do_strip_comments ; then
					"$CROSS_COMPILE"strip --remove-section .comment "$i"
				fi
			esac
			if $strip_debug ; then
				name=$(printf "%s" "$i" | sed 's@/@_@')
				"$CROSS_COMPILE"objcopy --only-keep-debug "$i" lib/debug/"$name".dbg &&
				"$CROSS_COMPILE"strip --strip-debug --strip-unneeded "$i" &&
				"$CROSS_COMPILE"objcopy --add-gnu-debuglink=lib/debug/"$name".dbg "$i"
			fi
		done
		if $strip_debug ; then
			test $(ls lib/debug | wc -l) = 0 && rm -rf lib/debug || \
			chmod 664 lib/debug/*
		fi
		if $strip_debug || $butch_do_strip_comments ; then
			printf "%s: done\n" "$(timestamp)"
		fi
	fi

	if $butch_do_delete_libtool_archives ; then
		# remove libtool .la files
		for i in lib/*.la ; do
			echo "removing .la file $i"
			rm -f "$i"
		done
	fi

	# here you could place some code that makes a tarball out of $butch_install_dir
	# moves the contents to / or create some sort of package file list.
	# e.g.
	if $butch_do_filelists ; then
		"$K"/bin/butch-genfilelist "$butch_package_name"
	fi

	if $butch_do_relocate ; then
		# now we make a symlink from each file into butch_prefix
		printf "%s: linking into rootfs...\n" "$(timestamp)"
		"$K"/bin/butch-relocate "$butch_package_name"
		printf "%s: done\n" "$(timestamp)"
	fi

	if $butch_do_create_tarball ; then
		(
		mkdir -p "$butch_pack_dest" && cd "$butch_pack_dest" && \
		"$K"/bin/butch-pack --xz "$butch_package_name"
		)
	fi

fi

printf "%s: done.\n" "`timestamp`"
[ -n "$start" ] && printf "total build time: %d seconds.\n" $(($(date +%s) - $start))
